//
// RS Game Framework
// Copyright © 2009 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFLECTION_CLASSBUILDER_HPP
#define RS_REFLECTION_CLASSBUILDER_HPP

#include "rs/reflection/Attribute.hpp"
#include "rs/reflection/AttributeProperties.hpp"
#include "rs/reflection/Class.hpp"
#include "rs/reflection/ClassBuilderInterface.hpp"
#include "rs/reflection/Constructor.hpp"
#include "rs/reflection/Method.hpp"
#include "rs/Portability.hpp"
#include "boost/preprocessor/arithmetic/inc.hpp"
#include "boost/preprocessor/punctuation/comma_if.hpp"
#include "boost/preprocessor/repetition.hpp"
#include <map>
#include <cstring>


#ifndef CONSTRUCTOR_MAX_ARITY
#   define CONSTRUCTOR_MAX_ARITY 5
#endif

#define BIND_CONSTRUCTOR(z, n, _) \
    template< typename TClass BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, typename TArg) > \
    ClassBuilder& BindConstructor(Boolean visit = true) { \
        Constructor constructor = \
            rs::reflection::internal::ConstructorFactory::Create \
            < \
                TClass BOOST_PP_COMMA_IF(n) \
                BOOST_PP_ENUM_PARAMS(n, TArg) \
            >(); \
        constructors_.push_back(constructor); \
        if (visit && visitor_) { \
            visitor_->BindConstructor(constructor); \
        } \
        \
        return *this; \
    }

namespace rs
{
    namespace reflection
    {    
        struct NullClassVisitor
        {
            RS_FORCE_INLINE void InitializeClass(Char8 const* name) { }
            
            RS_FORCE_INLINE void FinalizeClass() { }
            
            RS_FORCE_INLINE void BindConstructor(Constructor const& constructor) { }
            
            template< typename TAttribute, typename TClass >
            RS_FORCE_INLINE void BindAttribute(Char8 const* name, TAttribute TClass::* attribute, Attribute const& reflectedAttribute) { }
            
            template< typename TFunction >
            RS_FORCE_INLINE void BindMethod(Char8 const* name, TFunction method, Method const& reflectedMethod) { }
        };
        
        
        template< typename TClassVisitor >
        class ClassBuilder : public hidden::ClassBuilderInterface
        {
        private:
            
            struct StringCompare
            {
                Boolean operator()(Char8 const* lhs, Char8 const* rhs) {
                    return std::strcmp(lhs, rhs) <= 0;
                }
            };
            
            typedef std::map< Char8 const*, Attribute > AttributeContainer;
            typedef std::multimap< Char8 const*, Method, StringCompare > MethodContainer;
            typedef std::vector< Constructor > ConstructorContainer;
            
        public:
            
            ClassBuilder(Char8 const* className, Class const* parent = 0, TClassVisitor* visitor = 0);
            
            void FinalizeClassVisitor();
            
            Char8 const* GetClassName() const;
            
            Class const* GetParentClass() const;
            
            template< typename TAttribute, typename TClass >
            ClassBuilder& BindAttribute(Char8 const* name, TAttribute TClass::* attribute, Boolean visit = true);
            
            template< typename TFunction >
            ClassBuilder& BindMethod(Char8 const* name, TFunction method, Boolean visit = true);
            
            BOOST_PP_REPEAT(BOOST_PP_INC(CONSTRUCTOR_MAX_ARITY), BIND_CONSTRUCTOR, _)
            
            template< typename TClass >
            ClassBuilder& BindDestructor();
            
            Attribute* BuildAttributes() const;
                        
            Method* BuildMethods() const;
            
            ConstructorContainer const& GetConstructors() const;
            
            internal::Destructor GetDestructor() const;
            
            RsSize GetAttributeCount() const;
            
            RsSize GetMethodCount() const;
            
            RsSize GetConstructorCount() const;
                        
            ClassBuilder& operator[](AttributeProperties const& properties);
            
        private:
            
            AttributeContainer attributes_;
            MethodContainer methods_;
            ConstructorContainer constructors_;
            internal::Destructor destructor_;
            Char8 const* className_;
            Class const* parent_;
            Attribute* lastAttribute_;
            TClassVisitor* visitor_;
        };
    }
}


#define RS_REFLECTION_CLASSBUILDER_IMPLEMENTATION_GUARD
#include "rs/reflection/ClassBuilder.ipp"
#undef RS_REFLECTION_CLASSBUILDER_IMPLEMENTATION_GUARD


#undef BIND_CONSTRUCTOR
#undef CONSTRUCTOR_MAX_ARITY
#endif // RS_REFLECTION_CLASSBUILDER_HPP